/* io calls with ports definitions -  ports depending on the transmitter design
here all the calls of io processing with a port definition  



============================================================================
 # Copyright (C) 2008 2009 Robert Spilleboudt
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 ============================================================================
 */
#include <stdio.h>
#include <avr/io.h>

#include "util/lcd.h"
#include "io.h"
# include "rccl.h"
#include <util/delay.h>


//declaration of the external data, common to all the RCCL functions
extern struct rccl_data rc; 
void io_init(){ /*  ports initialization
	Each port pin consists of three Register bits: DDxn, PORTxn, and PINxn. As shown in "Register
	Description for I/O Ports" on page 87, the DDxn bits are accessed at the DDRx I/O address, the
	PORTxn bits at the PORTx I/O address, and the PINxn bits at the PINx I/O address.
	The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written logic one,
	Pxn is configured as an output pin. If DDxn is written logic zero, Pxn is configured as an input
	pin.
	If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is
	activated. To switch the pull-up resistor off, PORTxn has to be written logic zero or the pin has to
	be configured as an output pin. The port pins are tri-stated when a Reset condition becomes
	active, even if no clocks are running.
	If PORTxn is written logic one when the pin is configured as an output pin, the port pin is driven
	high (one). If PORTxn is written logic zero when the pin is configured as an output pin, the port
	pin is driven low (zero).*/
	
	//******fill here  the initializations of the ports and the variables ;  this is where the  Pins are specified
	//configure output PPM
	DDRG |= 1<<PG2 | 1<<PG3; /* set PG2 to output DDR=data direction register */
	//configure input  buttons @B..
	PORTA |= 1<<PA0 | 1<<PA1 |1<<PA2 |1<<PA3 |1<<PA4 |1<<PA5 |1<<PA6 |1<<PA7;
	PORTB |= 1<<PB4 |  1<<PB5 | 1<<PB6 | 1<<PB7 ;//activate pull-up
	PORTC |=  1<<PC7;
	PORTD |= 1<<PD0|  1<<PD1  |  1<<PD4 |  1<<PD5|  1<<PD6| 1<<PD7;
	PORTG |= 1<<PG3;
	//digital trim parameters
	PORTE |= 1<<PE2 |1<<PE3 | 1<<PE4 | 1<<PE6| 1<<PE7; //pull up
	
	//beep PC7
	DDRC |= 1<<PC7; //as output
	PORTC &= ~(1<<PC7); //initial value 0 = no beep
	rc.beep=0; //no beep
	
	// power maintened on by the avr
	//DDRG |= 1<<PG0;
	//PORTG |= (1<<PG0) ; // set to to 1 to maintain the power power
	POWER_DDR  |=   (1<< POWER_PIN);
		
	uint8_t i;
	for (i=0;i<DTRIM_N;i++){
		rc.io_timer[i]=0;
		rc.io_state[i]=0;
	}
	
	
	//adc initialization
	ADCSRA |=  (1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2)    ; //Prescaler 128  , correct for  CPU 16 Mhz
	// ET-Stamp external voltage reference AREF tuned with a potentiometer  ADMUX: REFS0=0 REFS1=0
	ADCSRA |= (1 << ADEN); //enable ADC

	//tick
	rc.io_tick=0; 
	
}
void io_power(int power_on){
	if (power_on==1){ //power on
		
		POWER_PORT |=   (1<< POWER_PIN);  // set to to 1 to maintain the power power;
		ee_putchar(EE_POWER, '$');
		#ifdef UART0
		printf_P(PSTR("io_power=1 on \n") );
		#endif
	}
	if (power_on==0){ //power off
		#ifdef UART0
		printf_P(PSTR("io_power=0  off\n") );
		_delay_ms(200);
		#endif
		ee_putchar(EE_POWER, 0x00); // the eeprom is erased by avrdude -> back to normal 
		_delay_ms(30);// to be sure the eeprom is written
		

		POWER_PORT &= ~(1<<POWER_PIN) ; // kill the power
		while(1){ //wait the death      beware: the brownout fuse is needed, to provide hysteresis and watchdog is disabled
			#ifdef UART0
			printf_P(PSTR("io_power=0  loop\n") );
			_delay_ms(200);
			#endif
			continue;
		}
		/*
		this "power" byte in EEPROM at MAX_PARAM+1 is
		-initialized to 0 by the avrdude programmer
		-set to $ during the power-on sequence
		-remains to $ in case of watchdog or any  reset
		-reset to 0 by the Power Off menu
		*/
	}
	if (power_on==2){ //avr start : check immediatly the power byte !!UART0 not yet available
		if (ee_getchar(EE_POWER) == '$') //this is probably a reset by the watchdog
			POWER_PORT |=   (1<< POWER_PIN);  // set to 1 to maintain the power ;
		else{ //this is a false restart of the AVR after the power off (energy remaining in the condensors)
			POWER_PORT &= ~(1<<POWER_PIN) ; // be sure to kill the power
			_delay_ms(500);
		}
	
	}
}
void io_adc_all(){ //ADC read
	uint8_t i;
	int xy[6];
	xy[1]=-TOINTx100;
	xy[3]=0;
	xy[5]=TOINTx100;
	
	 //read and calibrate the ADC inputs
	for (i=0;i<ADC_CH  ;i++){
		if (rc.adc_xa[i] < rc.adc_xb[i]){
			xy[0]=rc.adc_xa[i];
			xy[2]=rc.adc_xc[i];
			xy[4]=rc.adc_xb[i];
			rc.N_tx[ i  ] = curveS( io_adc(i),xy,6);
		}
		else{
			xy[0]=rc.adc_xb[i];
			xy[2]=rc.adc_xc[i];
			xy[4]=rc.adc_xa[i];
			rc.N_tx[ i  ] = -curveS( io_adc(i),xy,6);
		}
	}	
	rc.battery =  io_adc(7) ; // raw 
}
//***** simple  digitalIO********************************************
uint8_t io_swread_one(uint8_t port,uint8_t bit){// read port/bit and put result0/1
	if  ( bit_is_set(port,bit)>0)
		return 0;
	else
		return 1;
}
void io_swread(){//switch & buttons   simple ports reads without debouncing
	// fill here all the sw to read
	// reference from Tx self.L_tx=["H1","HS","BA","S1","S2","S3","S6","S4a","S4b","S5a","S5b", "B1"] 
	//rc.L_tx[2]= io_swread_one(PINA,7); //button @BA autotrim - now debounce is needed
	rc.L_tx[3]= io_swread_one(PINA,4); //@SW1
	rc.L_tx[4]= io_swread_one(PINA,5); //@SW2
	rc.L_tx[5]= io_swread_one(PINA,6); //@SW3
	rc.L_tx[6]= io_swread_one(PIND,4); //@SW6
	rc.L_tx[7]= io_swread_one(PINA,0); //@S4a
	rc.L_tx[8]= io_swread_one(PINA,1); //@S4b
	rc.L_tx[9]= io_swread_one(PINA,3); //@S5a
	rc.L_tx[10]= io_swread_one(PINA,2); //@S5b
	rc.L_tx[11]= io_swread_one(PING,3); //@B1
	
		
	
	
}
void io_set(){// output IO pins  depending on rc. variables
	
	// Other are not depending on RC variables, like PPM,Beep,PowerOff
	
/*	if(rc.L_tx[ 1]==0)   // sw PB2 lights the LED PB0 
		PORTB &= ~(1<<PB0);// LED on 
	else
		PORTB |= 1<<PB0; // LED off   */
	
}

void io_butread5( ){/* debouncing
	- this is processed in the rcloop , minimum every 5 msec
	 fill here all the buttons with debouncing
	- actions:
		debounce and put the result in the state variable
		wait on the ack from the menu program (use  io_getButton)
	
	*****fill here  all the boutons to debounce   example: _io_debounce(0,bit_is_set(PINB,2));
	
	io.h: 
		#define PARAM_N 3  // total number of buttons for the parameters  updatable in flight
	rccl.h
		uint8_t io_state[PARAM_N +2]; // state variable for a debounced button



	*/
	_io_debounce(MENU_SELECT,bit_is_clear(PINB,7)); //MENU_SELECT
	_io_debounce(1,bit_is_clear(PINB,4)); //MENU_BACK  
	_io_debounce(2,bit_is_clear(PINB,5)); //MENU_UP          
	_io_debounce(3,bit_is_clear(PINB,6)); //MENU_DOWN    
	_io_debounce(4,bit_is_clear(PINA,7)); // automatic trim @BA
	
	//the button @BA is debounced and put in a logical variable
	rc.L_tx[2] = io_getButton(4);
               
	                         
}
void io_butread100( ){/* fill here all the digital trims    processing every 100 msec
	- actions:
		2 buttons -> reset to 0
		1 button = one "click"
		if a button remains pushed during 0.7sec, clicks occurs at a higher rate
	*/
	
	/*use rc.clock_calc = how many rcloops / (1/100 minute)  typical  value 72 or 8.333 msec/cycle
	 counter -> 100 msec
	
	*/
	static uint16_t count;
	if (count > 0){
		count--;
		return;
	}
	if (rc.clock_calc>0)
		count= rc.clock_calc/CLOCK_100  ; // 100msec / CLOCK_TICK (
	
	//the digital trim for parameters (selection by buttons or menu) !sign + UP or RIGHT
	_io_tick(  0, bit_is_clear(PINE,4),bit_is_clear(PINE,3));// digital trim to update a parameter in flight
	_io_tick( 1, bit_is_clear(PIND,0),bit_is_clear(PIND,1));//digital trims for the sticks V1
	_io_tick(2, bit_is_clear(PIND,6),bit_is_clear(PIND,5));// @M2
	//_io_tick(3, bit_is_clear(PIND,7),bit_is_clear(PINE,2));// @M3
	_io_tick(3, bit_is_clear(PINE,2),bit_is_clear(PIND,7));// @M3
	_io_tick(4, bit_is_clear(PINE,7),bit_is_clear(PINE,6));// @M4 
	// test instructions for phase
	//printf ("io.c rc.phase=%i V1 (var 8) =%i  rc.slow_done=%i  _end=%i\n",rc.phase, rc.N_tx[8],rc.slow_done,rc.slow_end);
}	
void io_beep(){
	if (rc.beep ==0){
		PORTC&= ~(1<<PC7);
		 //beeper off   (connected to +5V)
		return;
	}
	rc.beep --;
	//test a no beep indicator
	PORTC |= 1<<PC7;
	
}
void io_beep_set(int duration){//sets the beeper for the duration in 100 msec
	rc.beep= duration *(rc.clock_calc/CLOCK_100 )  ;  
}
	

